use bincode::{serialize, deserialize};
use std::fs;
use std::path::Path;
use std::io::Read;
use std::io::Write;
use std::fmt;
use std::str;
use std::iter::Iterator;
// use std::sync::mpsc::channel;

use regex::Regex;
use uuid::Uuid;
use serde::{Deserialize, Serialize};
use dirs::home_dir;
use base64::decode as bde;
use base64::encode as ben;
use colored::Colorize;
use encoding::all::GBK;
use encoding::all::UTF_8;
use encoding::{DecoderTrap, Encoding};
use serde_json::Value;


use crate::CmdRun;
use crate::security::Cryptor;
use crate::log_utils;
use crate::net;
use crate::security;
use crate::output::WraperParser;

pub const STATUS_READY: i32 = 0;
pub const STATUS_RUN: i32 = 1;
pub const STATUS_EDN: i32 = -1;

#[allow(unused)]
pub const STATUS_SUSS: i32 = -2;

#[allow(unused)]
pub const STATUS_ERR: i32 = -3;
pub const BRD_TP_CMD: i32 = 0;
pub const BRD_TP_LIB: i32 = 1;
pub const OUTPUT_TO_BRD:u8 = 0b00;
pub const OUTPUT_TO_MANY_BRD:u8 = 0b01;
pub const OUTPUT_TO_LOG:u8 = 0b10;
pub const OUTPUT_END:u8 = 0b100;


lazy_static!{
    static ref HOME_DIR: String = {
        log_utils::log_init();
        let home = home_dir().unwrap().join("Brd-hub");
        if !home.exists() {
            let _ = fs::create_dir(&home);
        }
        home.to_str().unwrap().to_owned()
    };
    static ref BRD_SRC_RE: Regex = Regex::new(r#"chain://([\w:]+?)/([\w\-]{36})(/\w+)?"#).unwrap();
    static ref BRD_LOC_RE: Regex = Regex::new(r#"chain://(.+?):?(\d+)"#).unwrap();
    static ref BRD_TASK_RE: Regex = Regex::new(r#"([cmdapi]{3})://(\w+)@([\w,=]+)->(\d+)\|?.+?(wraper://.+@[\w=]+)*"#).unwrap();
    static ref BRD_TASK_RE_PLAIN: Regex = Regex::new(r#"([cmdapi]{3})://(\w+)->(\d+)(\s+?\|\s+?wraper://.+)"#).unwrap(); // TODO: re to parse plain text task string 
    static ref BRD_WRPER_RE:Regex = Regex::new(r#"\s+?\|\s+?(wraper://[\w\[\],"]+)"#).unwrap();
    static ref BLOCK_SEP_LINE: Regex = Regex::new(r#"=======| (.+) |======="#).unwrap();
    
}


#[allow(unused)]
#[derive(Serialize, Deserialize,Debug)]
pub struct Loc{
    pub uid:String,
    pub host:String,
    pub path:String,
}

#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct LocInfo{
    pub host:String,
    pub uids:Vec<String>,
}


#[derive(Serialize, Deserialize,Debug)]
pub struct TaskWraper{
    pub wraper:Vec<String>
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct Judger{
    field: String
}

#[derive(Serialize, Deserialize,Debug)]
pub struct Task{
    /*
    Task must like 
    output: 
        o01 : OUTPUT_TO_BRD
        o00 : OUTPUT_TO_MANY_BRD

        o10 : output to string to log
        o00 : output not to log
     api[main:/args_num/b64_args]->output
     cmd[main:/args_num/b64_args]->output
    */
    pub tp:i32,
    pub log:String,
    pub main:String,
    pub args:Vec<String>,
    pub output_tp:u8,
    pub status:i32,
    pub wraper:TaskWraper,
}

#[allow(unused)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Chain{
    pub loc: Loc,
    pub start_node: Loc,
    pub sub_chains:Vec<Chain>,
    pub resource:Vec<String>,
    pub log:String,
    pub action:String,
    pub task:Task,
}

impl Default for Task{
    fn default() -> Self{
        Self{
            status: STATUS_READY,
            tp: BRD_TP_CMD,
            args: Vec::new(),
            main: String::new(),
            log: String::new(),
            wraper: TaskWraper::default(),
            output_tp: OUTPUT_TO_LOG,
        }
    }
}
impl Default for TaskWraper {
    fn default() -> Self{
        Self{
            wraper: Vec::new()
        }
    }
}

impl Clone for TaskWraper{
    fn clone(&self) -> Self{
        Self{
            wraper: self.wraper.clone()
        }
    } 
}


impl <'a>Clone for Task{
    fn clone(&self) -> Self{
        Self{
            status: self.status,
            tp: self.tp,
            args: self.args.clone(),
            output_tp: self.output_tp.clone(),
            main: self.main.clone(),
            log:self.log.clone(),
            wraper: self.wraper.clone()
        }
    }    
}

impl Default for Loc{
    fn default() -> Self{
        let uid = Uuid::new_v4().to_string();
        let home = HOME_DIR.clone().to_string();
        let path = Path::new(&home).join(&uid).to_str().unwrap().to_string();
        Self{
            uid: uid,
            host: self::net::who_am_i(),
            path: path
        }
    }
}

impl Default for LocInfo{
    fn default() -> Self{
        Self{
            uids: Vec::new(),
            host: self::net::who_am_i()
        }
    }
}


impl Default for Chain{
    fn default() -> Self{
        let loc = Loc::default();
        Self{
            start_node: loc.clone(),
            loc:loc,
            sub_chains: Vec::new(),
            log:String::new(),
            resource: Vec::new(),
            task:Task::default(),
            action: "run".to_string(),
        }
    }
}


impl Loc{
    pub fn new(uid: &str) -> Self{
        let home = HOME_DIR.clone().to_string();
        let path = Path::new(&home).join(&uid).to_str().unwrap().to_string();
        Self{
            uid:uid.to_string(),
            host: self::net::who_am_i(),
            path:path
        }
    }
    pub fn with_uid_and_host(uid:&str, host:&str) -> Self{
        let mut s = Self::new(uid);
        s.host = host.to_string();
        s
    }

    pub fn to_string(&self) -> String{
        format!("chain://{}/{}", self.host,self.uid)
    }

    pub fn to_json(&self) -> String{
        let j = serde_json::to_string(self).unwrap();
        j.to_string()
    }

}

impl TaskWraper{
    pub fn to_string(&self) -> String{
        format!("{}", self)
    }
}
pub fn ls_brd() -> Vec<String>{
    let output = HOME_DIR.to_string();
    let mut li: Vec<String> = Vec::new();
    for entry in fs::read_dir(&output).expect("list dir error") {
        let en = entry.expect("list entry error");
        let name = en.file_name().to_str().unwrap().to_string();
        match Uuid::parse_str(&name) {
            Ok(_) => {
                li.push(name);
            }
            Err(_) => {}
        }
    }
    li
}

pub trait ChainData{
    fn to_task_wraper(&self) -> Option<TaskWraper>;
    fn to_loc(&self) -> Option<Loc>;
    fn to_chain(&self) -> Option<Chain>;
    fn to_task(&self) -> Option<Task>;
    fn chain_find(&self) -> Vec<Chain>;
    fn chain_load(&self) -> Option<Chain>;
    fn chain_load_json(&self) -> Option<Chain>;
    fn chain_load_pwd(&self, pwd:&str) -> Option<Chain>;
    fn chain_remove(&self) -> bool;
    fn args(&self) -> String;
    fn with_cmd(&self) -> Task;
    fn file_open(&self) -> Option<Vec<u8>>;
    fn file_open_str(&self) -> Option<String>;
    fn split_skip(&self, sep:&str,  c:char) -> Vec<String>;
    fn to_64(&self) -> String;
    fn from_64(&self) -> Option<String>;
    fn push_args<T>(&self, args:&Vec<T>) -> String
    where T: serde::Serialize + fmt::Display ;
}

pub trait ChainNet{
    fn action(&self, chain:&Chain) -> Option<Chain>;
}


impl <'a>ChainData for &'a str{
    fn to_64(&self) -> String{
        ben(self)
    }
    fn to_task_wraper(&self) -> Option<TaskWraper>{
        if self.trim().starts_with("wraper://") && self.contains("@"){
            if let Some(raw_json_b64) = self.trim().split("@").collect::<Vec<_>>().last(){
                if let Some(real_json) = raw_json_b64.from_64(){
                    return Some(TaskWraper{
                        wraper: serde_json::from_str(&real_json).unwrap()
                    });
                }
            }

            None
        }else{
            None
        }
    }
    fn from_64(&self) -> Option<String>{
        if let Ok(s) = bde(self){
            match UTF_8.decode(&s, DecoderTrap::Ignore){
                Ok(a) => Some(a),
                _ => Some(GBK.decode(&s, DecoderTrap::Ignore).unwrap())
            }
        }else{
            None
        }
    }

    fn split_skip(&self, sep:&str,  c:char) -> Vec<String>{
        let mut spliter:Vec<String> = Vec::new();
        let mut real_single = String::new();
        for s in self.split(sep){
            real_single.push_str(s);
            if real_single.contains(c) && real_single.chars().fold(0,|acc,x| {
                if x== c{
                    acc +1
                }else{
                    acc
                }
            } ) % 2 == 1{
                continue
            }else{
                let s = real_single.trim();
                if s.starts_with('"') && s.ends_with('"'){
                    spliter.push(s.to_owned()[1..s.len()-1].to_string());
                }else{
                    spliter.push(s.to_owned());
                }
                real_single = String::new();
            }
        }
        spliter
    }
    fn chain_load_json(&self) -> Option<Chain>{
        if self.trim().starts_with("{"){
            let brd: Chain = match serde_json::from_str(self){
                Ok(a) => a,
                Err(e) => {
                    log::error!("parse json from file error :{}", e);
                    return None;
                }
            };
            Some(brd)
        }else{
            None
        }
    }
    fn file_open_str(&self) -> Option<String>{
        if let Some(buf) = self.file_open(){
            Some(match UTF_8.decode(&buf, DecoderTrap::Ignore){
                Ok(a) => a,
                _ => GBK.decode(&buf, DecoderTrap::Ignore).unwrap()
            })
        }else{
            None
        }
    }
    fn file_open(&self) -> Option<Vec<u8>>{
        let output_path = Path::new(self);
        if output_path.exists(){
            if let Ok(mut f) = fs::File::open(output_path){
                let mut buf: Vec<u8> = Vec::new();
                let _ = f.read_to_end(&mut buf);
                return Some(buf);
            }
        }
        None
    }


    fn with_cmd(&self)-> Task{
        let mut b = Task::default();
        b.main = self.to_string();
        b.tp = BRD_TP_CMD;
        b
    }

    fn args(&self) -> String{
        ben(self.as_bytes())
    }

    fn chain_remove(&self) -> bool{
        if let Ok(_) = Uuid::parse_str(self){
            let home = HOME_DIR.to_string();
            let pp = Path::new(&home).join(self);
            let pp_task = Path::new(&home).join(&format!("{}.task", self));
            if pp_task.exists() {
                let _ = fs::remove_file(pp_task);
            }
            if pp.exists(){
                let _ = fs::remove_file(pp);
                return true;
            }

            
        }
        false
    }
    fn chain_find(&self) -> Vec<Chain>{
        let mut vs:Vec<Chain> = Vec::new();
        for u in ls_brd(){
            if let Some(b) = u.as_str().chain_load() {
                if b.loc.uid.contains(self) || b.loc.host.contains(self){
                    vs.push(b);
                }
            }
        }
        vs
    }

    fn to_loc(&self) -> Option<Loc>{
        /*
        must format like:  chain://host_or_ip:port/uuid;
        */
        if self.starts_with("chain://"){
            for cap in BRD_SRC_RE.captures_iter(self){
                let mut host = cap[1].to_string();
                if !host.contains(":"){
                    host = format!("{}:{}",&host, 54321);
                }
                let uid = cap[2].to_string();
                return Some(Loc::with_uid_and_host(&uid, &host));
            }
        }
        None
    }
    fn to_chain(&self) -> Option<Chain>{
        if self.trim().starts_with("chain://"){
            let mut chain:Chain = Chain::default();
            let mut found_chain = false;
            for cap in BRD_SRC_RE.captures_iter(self){
                let mut host = cap[1].to_string();
                if !host.contains(":"){
                    host = format!("{}:{}",&host, 54321);
                }
                let uid = cap[2].to_string();
                if cap.len() == 4{
                    chain.action = cap[4].to_string()[1..].trim().to_string()
                }
                let loc = Loc::with_uid_and_host(&uid, &host);
                chain.loc = loc;
                found_chain = true;
                break
            }
            if let Some(task) = self.to_task(){
                chain.task = task;
            }
            if found_chain{
                return Some(chain);
            }
        }
        None
    }
    fn chain_load(&self) -> Option<Chain>{
        /* This function load local brd file from HOME_DIR by uuid. if string is format with uuid v4
            uuid||pwd
            uuid
        */
        if self.len() < 36 {
            return None;
        }
        if let Ok(_) = Uuid::parse_str(&self[..36]){
            let home = HOME_DIR.to_string();
            if let Ok(mut f) = fs::File::open(Path::new(&home).join(&self[..36])){
                let mut buf = String::new();
                let _ = f.read_to_string(&mut buf);
                if buf.trim().starts_with("{"){
                    let brd: Chain = match serde_json::from_str(&buf){
                        Ok(a) => a,
                        Err(e) => {
                            log::error!("parse json from file error :{}", e);
                            return None;
                        }
                    };
                    Some(brd)
                }else{
                    if self.len() < 38{
                        return None;
                    }
                    let de =  security::Encryptor::new(&self[38..]);
                    let buf = de.de_b64(&buf);
                    if buf.len() == 0{
                        log::error!("error password :{}", &self[38..].red());
                        return None;
                    }
                    let mut brd: Chain = match serde_json::from_str(str::from_utf8(&buf).unwrap() ){
                        Ok(a) => a,
                        Err(e) => {
                            log::error!("parse json from file error :{}", e);
                            return None;
                        }
                    };
                    let task_path = brd.task_path();
                    if Path::new(&task_path).exists(){
                        brd.task.status = STATUS_EDN;
                    }
                    Some(brd)
                }
                
            }else{
                log::error!("{}","no uuid file in local ".red());
                None
            }
        }else{
            None
        }
    }

    fn chain_load_pwd(&self, pwd:&str) -> Option<Chain>{
        format!("{}||{}", self, pwd).as_str().chain_load()
    }

    fn to_task(&self) -> Option<Task>{
        for cap in BRD_TASK_RE.captures_iter(self){
            let pre = cap[1].to_string();
            let tp = match pre.as_str(){
                "cmd" => BRD_TP_CMD,
                _ => BRD_TP_LIB
            };
            let main = cap[2].to_string();
            let args:Vec<String> = cap[3].to_string().split(",").map(|x|x.to_string()).collect();
            // let _c = cap[4].to_string();
            // log::info!("parse : {}", _c);
            let out:u8 = cap[4].to_string().parse().expect("not digtal");
            let mut b = Task::default();
            b.tp = tp;
            b.args = args;
            b.output_tp = out;
            b.main = main;
            if cap.len() > 5{
                let s = cap[5].to_string();
                log::info!("found wraper {}",&s);
                if let Some(w) = s.to_task_wraper(){
                    b.wraper = w
                };
            }
            return Some(b);
        }

        for cap in BRD_TASK_RE_PLAIN.captures_iter(self){
            let pre = cap[1].to_string();
            let tp = match pre.as_str(){
                "cmd" => BRD_TP_CMD,
                _ => BRD_TP_LIB
            };
            let main = cap[2].to_string();
            let args:Vec<String> = Vec::new();
            let out:u8 = cap[3].to_string().parse().expect("not digtal");
            let mut b = Task{
                tp:tp,
                args:args,
                output_tp :out,
                main:main,
                ..Task::default()
            };
            if cap.len() > 4{
                log::info!("found wrapper!");
                for _cap in BRD_WRPER_RE.captures_iter(&cap[4].to_string()){
                    let _wraper_str = _cap[1].to_string().replace("|", "").trim().to_string();
                    b.wraper.wraper.push(_wraper_str.replace("wraper://","").to_string());
                }
            }
            return Some(b);

        }
        None
        
    }

    fn push_args<T>(&self, args:&Vec<T>) -> String
    where T: serde::Serialize + fmt::Display {
        let _mp :Vec<String> = args.iter().map(|o|{
            if let Ok(a) = serialize(&o){
                ben(&a)
            }else{
                log::error!("serilize arg {} | failed ", o);
                "".to_string()
            }
        }).collect();
        format!("{}{}",self, _mp.join(","))
    }
}

impl ChainData for String {
    fn to_chain(&self) -> Option<Chain>{
        self.as_str().to_chain()
    }
    fn to_task_wraper(&self) -> Option<TaskWraper>{
        self.as_str().to_task_wraper()
    }
    fn to_64(&self) -> String{
        self.as_str().to_64()
    }

    fn from_64(&self) -> Option<String>{
        self.as_str().from_64()
    }

    fn split_skip(&self, sep: &str, c: char)-> Vec<String>{
        self.as_str().split_skip(sep, c)
    }
    fn chain_load_json(&self) -> Option<Chain>{
        self.as_str().chain_load_json()
    }
    fn file_open(&self) -> Option<Vec<u8>>{
        self.as_str().file_open()
    }
    fn file_open_str(&self) -> Option<String>{
        self.as_str().file_open_str()
    }

    fn chain_load_pwd(&self, pwd:&str) -> Option<Chain>{
        self.as_str().chain_load_pwd(pwd)
    }
    
    fn with_cmd(&self) -> Task {
        self.as_str().with_cmd()
    }

    fn args(&self) -> String{
        self.as_str().args()
    }
    fn push_args<T>(&self, args:&Vec<T>) -> String
    where T: serde::Serialize + fmt::Display{
        self.as_str().push_args(args)
    }
    fn chain_remove(&self) -> bool{
        self.as_str().chain_remove()
    }
    fn chain_load(&self) -> Option<Chain>{
        self.as_str().chain_load()
    }
    fn chain_find(&self) -> Vec<Chain>{
        self.as_str().chain_find()
    }
    fn to_loc(&self) -> Option<Loc>{
        self.as_str().to_loc()
    }

    fn to_task(&self) -> Option<Task>{
        self.as_str().to_task()
    }
}

impl Clone for Loc {
    fn clone(&self) -> Self {
        Self{
            uid:self.uid.clone(),
            path:self.path.clone(),
            host:self.host.clone(),
        }
    }
}
impl Clone for LocInfo {
    fn clone(&self) -> Self{
        Self{
            uids:self.uids.clone(),
            host: self.host.clone()
        }
    }
}
impl Clone for Chain{
    fn clone(&self) -> Self{
        Self{
            start_node: self.start_node.clone(),
            log:self.log.clone(),
            loc:self.loc.clone(),
            resource: self.resource.clone(),
            task: self.task.clone(),
            action: self.action.clone(),
            sub_chains:self.sub_chains.clone(),
        }
    }
}

impl Chain {
    pub fn pass<Net>(&mut self, chain_passer:&Net)  -> bool 
    where Net:  ChainNet + Send + Clone +'static,
    {
        if self.sub_chains.len()> 0{
            if let Some(buf) = self.task_path().file_open_str(){
                let pool = threadpool::ThreadPool::new(4);
                let wrap = buf.as_wraper();
                for one_new_arg in wrap.to_split("\n").to_vec(){
                    for chain in self.sub_chains.iter_mut(){
                        /*
                        sub chain will patch result from main_chain. then pass through passer.
                        */
                        chain.task.args::<String>(&vec![one_new_arg.clone()]);
                        let mut chain = chain.clone();
                        let passer_s = chain_passer.clone();
                        pool.execute(move||{
                            if chain.is_local(){
                                chain.run();
                            }else{
                                if let Some(reply) = passer_s.action(&chain){
                                    log::info!("reply: {}", reply);
                                }
                            }
                            
                            
                        })
                    }
                }
                pool.join();
                return true;
            }
        }
        false
    }
    pub fn is_this_node(&self) -> bool{
        let this_node = crate::net::who_am_i();
        if this_node == self.loc.host{
            return true;
        }
        false
    }
    pub fn is_local(&self) -> bool{
        if ["127.0.0.1", "localhost", "::"].contains(&self.loc.host.as_str()){
            return true;
        }
        false
    }

    pub fn log(&mut self, log:&str){
        self.task.log.push_str(&format!("\n{}", log));
    }

    pub fn to_json(&self) -> String{
        let j = serde_json::to_string(&self).unwrap();
        j.to_string()
    }
    pub fn save(&self) -> String{
        if let Ok(mut f) = fs::File::create(&self.loc.path){
            let _ = write!(f, "{}", self.to_json());
        }
        self.loc.uid.clone()
    }

    pub fn task_path(&self) -> String {
        Path::new(&format!("{}.task",self.loc.path)).to_str().unwrap().to_string()
    }
    pub fn task_action_path(&self) -> String{
        Path::new(&format!("{}.map",self.loc.path)).to_str().unwrap().to_string()    
    }

    pub fn task_action_record(&self, map:&std::collections::HashMap<String,String>){
        let path = self.task_action_path();
        if let Ok(mut f) = std::fs::File::create(path){
            let b = json!(map).to_string();
            let _ = f.write_all(&b.as_bytes());
        }
    }

    pub fn output_info(&self) -> Option<String>{
        let p = self.task_path();
        if Path::new(&p).exists() {
            if let Ok(f) = fs::metadata(&p){
                Some(format!("size:{} | perm:{:?}", f.len(), f.permissions()))
            }else{
                None
            }
        }else{
            None
        }
    }


    pub fn save_pwd(&self, key:&str) -> String{
        if let Ok(mut f) = fs::File::create(&self.loc.path){
            let json_str = self.to_json();
            let e = security::Encryptor::new(key);
            let en_str = e.en_b64(json_str.as_bytes());
            let _ = write!(f, "{}", en_str);
        }
        self.loc.uid.clone()
    }
    pub fn insert(&mut self, sub_brd:&Chain)-> usize{
        let mut s_chain = sub_brd.clone();
        s_chain.resource = self.resource.clone();
        s_chain.action = self.action.clone();
        s_chain.start_node = self.start_node.clone();
        self.sub_chains.push(s_chain);
        self.sub_chains.len()
    }

    pub fn remove(&mut self, key:&str) -> usize{
        if let Some(p) = self.sub_chains.iter().position(|b| b.loc.uid == key){
            self.sub_chains.remove(p);
        }
        self.sub_chains.len()
    }

    pub fn keys(&self) -> Vec<Loc> {
        self.sub_chains.iter().map(|l|l.loc.clone()).collect()
    }

    pub fn get(&self, key:&str) -> Option<Chain>{
        if let Some(p) = self.sub_chains.iter().position(|b| b.loc.uid.contains(key)){
            Some(self.sub_chains[p].clone())
        }else{
            None
        }
    }
    
    pub fn try_wraper(&self) -> bool{
        if self.task.wraper.wraper.len() > 0 {
            let output = self.task_path();
            if let Some(buf) = output.file_open_str(){
                let new_buf = buf.wraper_with(&self.task.wraper_to_string()).to_string();
                if let Ok(mut f) = fs::File::create(&output){
                    f.write_all(&new_buf.as_bytes()).expect("save wraper output error");
                    return true;
                }
            }
        }
        false
    }
}

pub trait TaskArgs<'a,T>
{
    fn set_args(&mut self, args:&Vec<T>);
    // fn get_args(&self) -> Vec<T>;
    
}

impl LocInfo{
    pub fn read_json(&mut self,val: Value) -> &mut Self{
        let res:LocInfo = match serde_json::from_value(val){
            Ok(a) => a,
            _ => {
                return self;
            }
        };
        *self = res.clone();
        self
    }
}
impl Task{
    
    fn _byte_to_t<T>(&self, bufs:Vec<Vec<u8>>) -> Vec<T>
    where T:  Default +Clone +serde::de::Deserialize<'static>,
    {
        let mut iter_vec = bufs.iter();
        let mut outs: Vec<T> = Vec::new();
        'next : loop{
            let buf:Vec<u8> = match iter_vec.next(){
                Some(a) => a.clone(),
                _ => {
                    break 'next
                }
            };
            let buffr:&'static [u8] = Box::leak(buf.into_boxed_slice());
            let obj:T = deserialize(buffr).unwrap();
            outs.push(obj.clone())
        }
     
        outs
    }


    pub fn set_args_from_bytes(&mut self, args:&Vec<Vec<u8>>){
        self.args = args.iter().map(|x|{
            ben(x)
        }).collect()
    }

    pub fn set_args<T>(&mut self, args:&Vec<T>)
    where T: serde::Serialize + fmt::Display {
        let mut err:Vec<usize> = Vec::new();
        self.args = args.iter().enumerate().filter_map(|(no,o)|{
            let arg = match serialize(&o){
                Ok(a) => {
                    ben(&a)
                },
                _ => {
                    err.push(no);
                    "".to_string()
                }
            };
            if arg.len() > 0{
                Some(arg)
            }else{
                None
            }
        }).collect();
        // objs 
        for n in err{
            self.log.push_str(&format!("\n{}",args[n]))
        }
        
    }

    pub fn get_args_as_bytes(&self) -> Vec<Vec<u8>>{
        /*
        reutrn multi vec < Stream > 
        you need to implement deserilized for Vec<u8>
        */
        self.args.iter().map(|x|{
            match bde(x.as_bytes()){
                Ok(a) => a,
                Err(_) => "not base64 format".as_bytes().to_vec()
            }
        }).collect()
    }

    pub fn get_args<T>(&self) -> Vec<T>
    where T: serde::Serialize + fmt::Display + Default +Clone +serde::de::Deserialize<'static>{
        let array_stream = self.get_args_as_bytes();
        self._byte_to_t(array_stream)
    }

    pub fn get_command(&self) -> String{
        format!("{} {} ",self.main, self.get_args::<String>().join(" "))
    }

    pub fn to_string(&self) -> String {
        format!("{}",self)
    }

    pub fn new_chain(&self) -> Chain{
        let mut brd = Chain::default();
        brd.task = self.clone();
        brd
    }


    pub fn api(main: &str) -> Self{
        let mut default_task = Self::default();
        default_task.main = main.to_string();
        default_task.tp = BRD_TP_LIB;
        default_task 
    }
    pub fn cmd(main: &str) -> Self{
        let mut default_task = Self::default();
        default_task.main = main.to_string();
        default_task.tp = BRD_TP_CMD;
        default_task
    }
    pub fn args<T>(&mut self, args:&Vec<T>) -> &mut Self
    where T: Serialize + fmt::Display
    {
        self.set_args::<T>(args);
        self
    }

    pub fn output(&mut self, output_tp:u8) -> &mut Self{
        self.output_tp = output_tp;
        self
    }
    pub fn wraper_to_string(&self) -> String{
        if self.wraper.wraper.len()> 0{
            let s = self.wraper.wraper[1..].iter().fold(String::from(self.wraper.wraper[0].to_64()), |acc, x| format!("{} | {} ", acc,x.to_64()));
            s.to_string()
        }else{
            "".to_string()
        }
        
    }
    pub fn wraper(&mut self,main:&str, args:Vec<&str>)-> &mut Self{
        self.wraper.wraper.push(format!("{},{}", main, args.iter().map(|x| format!("\"{}\"",x)).collect::<Vec<String>>().join(",") ));
        self
    }
    pub fn exists_wrapper(&self) -> bool{
        if self.wraper.wraper.len() > 0{
            true
        }else{
            false
        }
    }
}


impl fmt::Display for Loc{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "chain:://{}/{}", self.host, self.uid)
    }
}
impl fmt::Display for Chain{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let sta = match self.task.status {
            -3 => format!("failed").on_red().green().to_string(),
            -2 => format!("Suss").on_yellow().bold().to_string(),
            -1 => format!("End").yellow().bold().to_string(),
            0 => format!("Ready"),
            _ => format!("running").green().bold().to_string(),
        };
        let head = format!("sub: {} | status: {} | {:?}",self.sub_chains.len(), sta, self.output_info());
        write!(f, "\n{}\n{}\n\t{}\n\t{}", head.on_yellow().black().bold(),self.loc, self.task, self.task.wraper)
    }
}

impl fmt::Display for TaskWraper{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let raw_json = serde_json::json!(self.wraper).to_string();
        let wrap_names = self.wraper.iter().filter_map(|x|{
            let s = x.split(",").map(|x|x.to_string()).collect::<Vec<String>>();
            if let Some(x) = s.first(){
                Some(x.to_string())
            }else{
                None
            }
        }).map(|x| x.to_string()).collect::<Vec<_>>().join("-");
        write!(f, "wraper://{}@{}",wrap_names,raw_json.to_64())
    }
}

impl fmt::Display for Task{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let wraper_str:String = if self.wraper.wraper.len()>0{
            format!("| {}", self.wraper)
        }else{
            String::new()
        };
        if self.tp == BRD_TP_CMD{
            write!(f, "cmd://{}@{}->{}{}", self.main, self.args.join(","), self.output_tp, &wraper_str)
        }else{
            write!(f, "api://{}@{}->{}{}", self.main, self.args.join(","), self.output_tp, &wraper_str)
        }
    }
}


#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
